home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1996 September
/
MACPOWER-1996-09.ISO.7z
/
MACPOWER-1996-09.ISO
/
第2特集:プラグイン大集合
/
PIC2 Save
/
p2savehi.c
< prev
next >
Wrap
Text File
|
1995-01-16
|
13KB
|
732 lines
/*
* PIC2 高圧縮/ベタフォーマットの展開 by やなぎさわ
*
*/
#include "pic2.h"
/* 現在のP2の中の変数のコピー (^^; */
static ushort bit_buf;
static short n_bit_buf;
static long xw;
static long ymax;
static uchar *fbufp;
static long n_fbuf;
static long len;
static P2 *p2;
static pix *vram_prev;
static pix *vram_now;
static pix *vram_next;
static schar *flag_now;
static schar *flag_next;
static pix (_HUGE_ * cache)[N_CACHE];
static ushort *cache_pos;
static ushort cache8_pos;
static short ynow;
static long chain_pos;
static char *chain_buff;
static pix (*write_color)( pix x);
/* エラー時の脱出用 */
static jmp_buf jmp_env;
/*
* 1バイト ファイルに書き出し
*/
static void
write_byte( uchar a)
{
*fbufp++ = a;
if ( --n_fbuf == 0) {
fbufp = p2->fbuf;
n_fbuf = N_FBUF;
if ( write_file( p2, fbufp, N_FBUF) != N_FBUF) {
p2errno = p2->errno = dskFulErr;//ENOSPC;
longjmp( jmp_env, 1);
}
}
n_bit_buf = 8;
}
/*
* ビットのバッファのフラッシュ
*/
static void
bit_buf_flush( void)
{
if ( n_bit_buf > 0) {
bit_buf <<= n_bit_buf;
write_byte(bit_buf);
}
}
/*
* ファイルバッファのフラッシュ
*/
static void
fbuf_flush( void)
{
long n;
bit_buf_flush();
write_byte( 0);
n = N_FBUF - n_fbuf;
if ( write_file( p2, p2->fbuf, n) != n) {
longjmp( jmp_env, 1);
}
}
/* size ビット n の下位から書き出します */
static const ushort bit_mask[] = {
0,
0x0001,
0x0003,
0x0007,
0x000f,
0x001f,
0x003f,
0x007f,
0x00ff,
0x01ff,
0x03ff,
0x07ff,
0x0fff,
0x1fff,
0x3fff,
0x7fff,
0xffff,
};
/*
* 'size'bit nをかき出す
*/
static void
bit_write( long size, long n)
{
while ( size >= n_bit_buf) {
size -= n_bit_buf;
bit_buf = ( bit_buf << n_bit_buf)
+ (bit_mask[n_bit_buf] & (n >> size));
write_byte( bit_buf);
}
if ( size > 0) {
bit_buf = ( bit_buf << size) + (bit_mask[size] & n);
n_bit_buf -= size;
}
}
static const unsigned short len_data[8][2]= {
1, 0,
1, 0,
3, 4,
3, 5,
5, 24,
5, 25,
5, 26,
5, 27,
};
/*
* 長さ書きだし
*/
static void
write_length( long n)
{
long a;
long b;
n++;
if ( n < 8) {
bit_write( len_data[n][0], len_data[n][1]);
} else {
a = 0;
b = 2;
while (n > b - 1) {
a = a + 1;
b = b * 2;
}
bit_write( a + 1, 0xfffffffe);
if ( a > 0) bit_write(a, n - b / 2);
}
}
/*
* 連鎖の圧縮
*/
static void
press_chain( long x)
{
pix cc = vram_now[x ];
if ( ynow - 1 == ymax) {
bit_write( 1, 0);
return;
}
if ( flag_next[ x] == 1 && vram_next[ x] == cc) {
flag_next[ x] = -1;
bit_write( 2, 3);
} else if ( flag_next[ x - 1] == 1 && vram_next[ x - 1] == cc) {
flag_next[ x - 1] = -1;
bit_write( 4, 11);
} else if ( flag_next[ x + 1] == 1 && vram_next[ x + 1] == cc) {
flag_next[ x + 1] = -1;
bit_write( 4, 9);
} else if ( flag_next[ x - 2] == 1 && vram_next[ x - 2] == cc) {
flag_next[ x - 2] = -1;
bit_write( 4, 10);
} else if ( (flag_next[ x + 2] == 1 && vram_next[ x + 2] == cc)
&& !( flag_now[ x + 2] != 0 && vram_now[ x + 2] == cc)
) {
flag_next[ x + 2] = -1;
bit_write( 4, 8);
} else {
bit_write( 1, 0);
}
}
/*
* 連鎖の圧縮(ただし結果はバッファに入る)
*/
static void
press_chain2( long x)
{
pix cc = vram_now[x ];
if ( ynow - 1 == ymax) {
chain_buff[ chain_pos++] = 0;
return;
}
if ( flag_next[ x] == 1 && vram_next[ x] == cc) {
flag_next[ x] = -1;
chain_buff[ chain_pos++] = 1;
} else if ( flag_next[ x - 1] == 1 && vram_next[ x - 1] == cc) {
flag_next[ x - 1] = -1;
chain_buff[ chain_pos++] = 2;
} else if ( flag_next[ x + 1] == 1 && vram_next[ x + 1] == cc) {
flag_next[ x + 1] = -1;
chain_buff[ chain_pos++] = 3;
} else if ( flag_next[ x - 2] == 1 && vram_next[ x - 2] == cc) {
flag_next[ x - 2] = -1;
chain_buff[ chain_pos++] = 4;
} else if ( (flag_next[ x + 2] == 1 && vram_next[ x + 2] == cc)
&& !( flag_now[ x + 2] != 0 && vram_now[ x + 2] == cc)
) {
flag_next[ x + 2] = -1;
chain_buff[ chain_pos++] = 5;
} else {
chain_buff[ chain_pos++] = 0;
}
}
/*
* 連鎖バッファのフラッシュ
*/
static void
chain_flush( void)
{
long i;
for ( i = 0; i < chain_pos; i++){
switch ( chain_buff[i]) {
case 0: bit_write( 1, 0); break;
case 1: bit_write( 2, 3); break;
case 2: bit_write( 4, 11); break;
case 3: bit_write( 4, 9); break;
case 4: bit_write( 4, 10); break;
case 5: bit_write( 4, 8); break;
}
}
chain_pos = 0;
}
/*
* 15bit色の書き出し
*/
static void
write_color15( pix x)
{
pix cc;
long j,k,m;
k = vram_now[x-1] >> 8;
cc = vram_now[ x];
m = cache_pos[k];
for ( j = 0; j < N_CACHE; j++) {
if ( cache[k][ ( m + j) & (N_CACHE-1)] == cc) break;
}
if ( j == N_CACHE) {
m = (m - 1) & (N_CACHE-1);
cache_pos[k] = m;
cache[k][m] = cc;
bit_write( 1, 0);
bit_write( 15, cc / 2);
} else {
bit_write( 1, 1);
bit_write( 6, j);
}
}
#if 0
/*
* 16(8)bit色の書き出し
*/
static void
write_color8( uchar cc)
{
uchar *cache8 = (uchar *)(cache_pos + 256);
short i;
for ( i = 0; i < 8; i++) {
if ( cache8[(i + cache8_pos) & 7] == cc) break;
}
if ( i == 8) {
cache8_pos = (cache8_pos - 1) & 7;
cache8[ cache8_pos] = cc;
bit_write( 1, 0);
bit_write( 8, cc);
} else {
bit_write( 1, 1);
bit_write( 3, i);
}
}
#endif
static void
write_color8( uchar cc)
{
uchar *cache8 = (uchar *)(cache_pos + 256);
short i,j;
for ( i = 0; i < 16; i++) {
if ( cache8[ i] == cc) break;
}
for ( j = i; j > 0; j--) {
cache8[ j] = cache8[ j - 1];
}
cache8[0] = cc;
if ( i == 16) {
bit_write( 1, 0);
bit_write( 8, cc);
} else {
bit_write( 1, 1);
bit_write( 4, i);
}
}
#define N_CACHE8_S 4
#define N_CACHE8 (1<<N_CACHE8_S)
#if 0
static void
write_color16( pix x)
{
pix cc;
long j,k,m;
k = vram_now[ x - 1] & 255;
cc = vram_now[ x];
m = cache_pos[k];
for ( j = 0; j < N_CACHE8; j++) {
if ( cache[k][ ( m + j) & (N_CACHE8-1)] == cc) break;
}
if ( j == N_CACHE8) {
m = (m - 1) & (N_CACHE8-1);
cache_pos[k] = m;
cache[k][m] = cc;
bit_write( 1, 0);
write_color8( cc >> 8);
write_color8( cc & 255);
/* bit_write( 16, cc); */
} else {
bit_write( 1, 1);
bit_write( N_CACHE8_S, j);
}
}
#endif
static void
write_color16( pix x)
{
pix cc;
short j,k,i;
k = vram_now[ x - 1] & 255;
cc = vram_now[ x];
for ( j = 0; j < N_CACHE8; j++) {
if ( cache[k][j] == cc) break;
}
for ( i = j; i > 0; i--) {
cache[k][i] = cache[k][i - 1];
}
cache[k][0] = cc;
if ( j == N_CACHE8) {
bit_write( 1, 0);
write_color8( cc >> 8);
write_color8( cc & 255);
} else {
bit_write( 1, 1);
bit_write( N_CACHE8_S, j);
}
}
/*
* 24bit色の書き出し
*/
static void
write_color24( pix x)
{
pix cc;
long j,k,m;
k = vram_now[ x - 1] >> 16;
cc = vram_now[ x];
m = cache_pos[k];
for ( j = 0; j < N_CACHE; j++) {
if ( cache[k][ ( m + j) & (N_CACHE - 1)] == cc) break;
}
if ( j == N_CACHE) {
m = (m - 1) & (N_CACHE - 1);
cache_pos[k] = m;
cache[k][m] = cc;
bit_write( 1, 0);
bit_write( 24, cc);
} else {
bit_write( 1, 1);
bit_write( 6, j);
}
}
/* 構造体アクセスをケチするため */
static void
para_out( void)
{
fbufp = p2->fbufp;
n_fbuf = p2->n_fbuf;
bit_buf = p2->bit_buf;
n_bit_buf = p2->n_bit_buf;
len = p2->aa;
chain_pos = p2->cc;
ymax = SHORT2short( p2->blk.y_wid) - 1;
xw = SHORT2short( p2->blk.x_wid);
write_color = (pix (*)(pix))p2->func;
ynow = p2->ynow;
vram_prev = p2->vram_prev + 4;
vram_now = p2->vram_now + 4;
vram_next = p2->vram_next + 4;
flag_now = p2->flag_now + 4;
flag_next = p2->flag_next + 4;
cache8_pos = p2->data;
cache = (pix (_HUGE_ *)[N_CACHE])p2->cache;
chain_buff = (char *)p2->mulu_tab;
cache_pos = p2->cache_pos;
}
static void
para_in( void)
{
void *p;
p2->fbufp = fbufp;
p2->n_fbuf = n_fbuf;
p2->bit_buf = bit_buf;
p2->n_bit_buf = n_bit_buf;
p2->func = (pix (*)(pix))write_color;
p2->aa = len;
p2->cc = chain_pos;
p2->ynow = ynow;
p2->data = cache8_pos;
p = p2->vram_prev;
p2->vram_prev = p2->vram_now;
p2->vram_now = p2->vram_next;
p2->vram_next = p;
p = p2->flag_now;
p2->flag_now = p2->flag_next;
p2->flag_next = p;
}
/*
* 1行圧縮
*/
static void
line_press2( void)
{
long x,a;
pix cc;
if ( SHORT2short( p2->header.depth) == 8) {
cc = vram_now[ xw * 2 - 2];
cc = cc * 256 + vram_now[ xw * 2 - 1];
} else {
cc = vram_now[ xw - 1]; /* ひとつ前の色 */
}
vram_next[ -1] = cc;
/* 変化点をマーク */
for ( x = 0; x < xw; x++) {
pix c = vram_next[ x];
if ( cc != c) {
flag_next[ x] = 1;
cc = c;
} else flag_next[ x] = 0;
}
for ( x = 0; x < xw; x++) {
a = flag_now[ x];
if ( a == 1) { /* 変化点 */
if ( len >= 1023) len++;
write_length( len);
chain_flush();
len = 0;
write_color( x);
press_chain( x);
} else if ( a == 0) {
len++;
} else {
press_chain2( x);
if ( chain_pos == 1023) {
write_length( 1023);
chain_flush();
len = 0;
}
}
}
}
/*
* 行単位の圧縮
* 始めのと最終ラインの処理もする
*/
static long
line_press( P2 *pp2, pix **line)
{
if ( setjmp( jmp_env) != 0) return ( -1);
p2 = pp2;
para_out();
if ( SHORT2short( pp2->header.depth) == 8) {
long i,j;
xw = (xw + 1) / 2;
for ( i = j = 0; i < xw; i++) {
ushort hi = vram_next[ j++];
ushort low = vram_next[ j++];
vram_next[ i] = hi * 256 + low;
}
}
if ( ynow == 0) { /* 先頭ラインの時 */
long x;
pix cc = 0;
/* フラグなどの初期化 */
memset( cache, 0, 256 * sizeof( cache[0]));
memset( cache_pos, 0, 8 * 8 * 8 * sizeof( cache_pos[0]));
/* 変化点をマーク */
vram_next[ -1] = cc;
for ( x = 0; x < xw; x++) {
pix c = vram_next[ x];
if ( cc != c) {
flag_next[ x] = 1;
cc = c;
} else flag_next[ x] = 0;
}
fbufp = p2->fbuf;
n_fbuf = N_FBUF;
n_bit_buf = 8;
bit_buf = 0;
chain_pos = 0;
cache8_pos = 0;
len = 0;
} else { /* 2ライン目から実際にセーブをする。これは1ライン先のデータが必要だから */
line_press2();
}
if ( ynow == ymax) {
/* 最後のラインの時は次のラインはもう無いので、これをセーブ */
ynow++;
para_in();
para_out();
if ( SHORT2short( pp2->header.depth) == 8) xw = (xw + 1) / 2;
line_press2();
}
/* 次のデータを入れて欲しいライン (vram_prevは次回 vram_nextになる)*/
if ( line != NULL) *line = vram_prev;
ynow++;
if ( ynow - 1 < ymax) { /* 最終ライン(終り)でなければ */
para_in(); /* p2にパラメータ入れる(戻す) */
return ( ynow);
} else { /* おわり */
para_in(); /* p2にパラメータ入れる(戻す) */
p2errno = 0;
if ( len >= 1023) len++;
write_length( len);
chain_flush();
fbuf_flush(); /* bitバッファを書き出して */
return ( -2); /* おわり */
}
}
/*
* 高速圧縮部の初期化
*/
long
p2sf_sv_init( P2 *p2, pix **line)
{
p2->ynow = 0;
/* 色の記録関数のセット */
switch ( SHORT2short( p2->header.depth)) {
case 24:
p2->func = (pix (*)())write_color24;
break;
case 15:
p2->func = (pix (*)())write_color15;
break;
case 8:
p2->func = (pix (*)())write_color16;
break;
default:
p2errno= p2->errno = P2E_BADFORM;
break;
}
/* 次ライン関数をセット */
p2->nextline = line_press;
if ( line != NULL) *line = p2->vram_next + 4;
p2errno = 0;
seek_file( p2, p2->next_pos + SIZE_OF_BLK);
if ( p2errno == 0) return ( 0);
return ( -1);
}
/***/
/*
* ベタの1ライン圧縮
*/
static long
beta_line_press( P2 *pp2, pix **line)
{
long i,xw,ymax;
uchar *p;
pix *pc;
p2 = pp2;
ynow = p2->ynow;
xw = SHORT2short( p2->blk.x_wid);
ymax = SHORT2short( p2->blk.y_wid) - 1;
if ( raw_beta == 0) { /* 他と同じ */
switch ( SHORT2short( p2->header.depth)) {
case 24:
pc = p2->vram_now;
p = (uchar *)p2->vram_prev;
for ( i = 0; i < xw; i++, pc++) {
*p++ = *pc >> 16;
*p++ = *pc >> 8;
*p++ = *pc;
}
if ( write_file( p2, p2->vram_prev, xw * 3) != xw * 3) return ( -1);
break;
case 15:
pc = p2->vram_now;
p = (uchar *)p2->vram_prev;
if ( memcmp( p2->blk.id, "P2BM", 4) == 0) {
for ( i = 0; i < xw; i++, pc++) {
*p++ = *pc >> 8;
*p++ = *pc;
}
} else {
for ( i = 0; i < xw; i++, pc++) {
*p++ = *pc;
*p++ = *pc >> 8;
}
}
if ( write_file( p2, p2->vram_prev, xw * 2) != xw * 2) return ( -1);
break;
case 8:
pc = p2->vram_now;
p = (uchar *)p2->vram_prev;
for ( i = 0; i < xw; i++) {
*p++ = *pc++;
}
if ( write_file( p2, p2->vram_prev, xw) != xw) return ( -1);
break;
}
if ( line != NULL) *line = p2->vram_now;
} else { /* ベタ */
switch ( SHORT2short( p2->header.depth)) {
case 24:
if ( write_file( p2, p2->vram_now, xw * 3) != xw * 3) return ( -1);
break;
case 15:
if ( write_file( p2, p2->vram_now, xw * 2) != xw * 2) return ( -1);
break;
case 8:
if ( write_file( p2, p2->vram_now, xw) != xw) return ( -1);
break;
}
*line = p2->vram_now;
}
p2->ynow++;
if ( p2->ynow > ymax) return ( -2);
return ( p2->ynow);
}
/*
* ベタ圧縮の初期化
*/
long
p2b_sv_init( P2 *p2, pix **line)
{
p2->ynow = 0;
*line = p2->vram_now;
p2->nextline = beta_line_press;
p2errno = 0;
seek_file( p2, p2->next_pos + SIZE_OF_BLK);
if ( p2errno == 0) return ( 0);
return ( -1);
}
/* eof */